Service.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. "use client";
  2. import { getWheelApi } from "@/api/cashWheel";
  3. import { ServiceTypes } from "@/api/customservice";
  4. import { userInfoApi } from "@/api/login";
  5. import { lredPacketApi, redPacketApi } from "@/api/promo";
  6. import { getGiveInfoApi } from "@/api/slots";
  7. import UserRecharge, { ModalRefProps, Timeout } from "@/components/ModalPopup/RechargeModal";
  8. import RedPacketModal, { RedPacketModalProps } from "@/components/ModalPopup/RedPacketModal";
  9. import SignInModal, { SignInModalProps } from "@/components/ModalPopup/SignInModal";
  10. import SlotsModal, { SlotModalRefProps } from "@/components/ModalPopup/SlotsModal";
  11. import WheelModal, { WheelModalProps } from "@/components/ModalPopup/WheelModal";
  12. import { useEventPoint } from "@/hooks/useEventPoint";
  13. import { Link } from "@/i18n/routing";
  14. import { useFirstPayStore } from "@/stores/useFirstPayStore";
  15. import { useGlobalNoticeStore } from "@/stores/useGlobalNoticeStore";
  16. import { useSignStore } from "@/stores/useSignStore";
  17. import useWheelStore from "@/stores/useWheelStore";
  18. import { getToken } from "@/utils/Cookies";
  19. import { useRequest } from "ahooks";
  20. import { Badge } from "antd-mobile";
  21. import { useTranslations } from "next-intl";
  22. import Image from "next/image";
  23. import { FC, useEffect, useRef, useState } from "react";
  24. interface Props {
  25. services: ServiceTypes[];
  26. }
  27. /**
  28. * 免费送活动
  29. */
  30. const SlotSection = () => {
  31. const slotsRef = useRef<SlotModalRefProps | null>(null);
  32. const getSlots = async () => {
  33. const token = getToken();
  34. if (token) {
  35. const result = await getGiveInfoApi();
  36. return result.data;
  37. } else {
  38. return Promise.resolve({});
  39. }
  40. };
  41. const { data: slots, run: slotRun } = useRequest<any, any>(getSlots, {
  42. pollingInterval: 2000,
  43. pollingErrorRetryCount: 1,
  44. pollingWhenHidden: false,
  45. });
  46. const slotHandler = () => {
  47. slotsRef.current?.onOpen(slots);
  48. };
  49. return (
  50. <>
  51. {slots?.id ? (
  52. <img
  53. src={"/slots/slots-icon.gif"}
  54. className={"mb-[0.2778rem] w-[100%]"}
  55. onClick={slotHandler}
  56. />
  57. ) : null}
  58. {/*随机送*/}
  59. <SlotsModal ref={slotsRef} onAfterHandler={slotRun} />
  60. </>
  61. );
  62. };
  63. /**
  64. * 轮盘
  65. */
  66. const WheelSection = ({ onDestory }: any) => {
  67. const wheelModalRef = useRef<WheelModalProps | null>(null);
  68. const { wheelStatus, wheelCurrent, setWheel } = useWheelStore((state) => ({
  69. wheelStatus: state.status,
  70. wheelCurrent: state.currentWheel,
  71. setWheel: state.setWheel,
  72. }));
  73. useEffect(() => {
  74. setWheel().then((data) => {
  75. if (data && useWheelStore.getState().status === 1) {
  76. wheelModalRef.current?.onOpen(data);
  77. }
  78. });
  79. }, []);
  80. return (
  81. <>
  82. {wheelStatus === 2 ? (
  83. <Link
  84. href={"/cashWheel"}
  85. className={
  86. "mb-[0.2778rem] flex h-[0.54rem] w-[0.54rem] items-center" +
  87. " justify-center rounded-[50%] bg-gradient-to-b from-[#0575e6] to-[#00f260]"
  88. }
  89. >
  90. <Image src={"/wheels/wheel-icon.gif"} alt={"wheel"} width={100} height={100} />
  91. </Link>
  92. ) : null}
  93. {/* 轮盘弹窗 */}
  94. <WheelModal ref={wheelModalRef} />
  95. </>
  96. );
  97. };
  98. /**
  99. * 首充
  100. */
  101. const PaySection = () => {
  102. const token = getToken();
  103. const { firstPay, getPayData } = useFirstPayStore((state) => {
  104. return {
  105. firstPay: state.first_pay,
  106. getPayData: state.getPayData,
  107. };
  108. });
  109. const userRechargeRef = useRef<ModalRefProps>(null);
  110. // 首充活动
  111. // const getPayInfo = async (): Promise<PayDataType> => {
  112. // if (token) {
  113. // const result = await getPaysApi();
  114. // return result.data;
  115. // } else {
  116. // return Promise.resolve({
  117. // first_pay: [],
  118. // pay: [],
  119. // });
  120. // }
  121. // };
  122. // const getPayInfo = async (): Promise<PayDataType> => {};
  123. const { data, run: payRun } = useRequest(getPayData, {
  124. pollingErrorRetryCount: 1,
  125. pollingWhenHidden: false,
  126. });
  127. return (
  128. <>
  129. {firstPay.map((item, index) => {
  130. return (
  131. <div
  132. key={index}
  133. className={`mb-[0.2778rem] flex cursor-pointer flex-col items-center`}
  134. >
  135. <img
  136. className={"w-[0.54rem]"}
  137. src="/hby/recharge.png"
  138. onClick={() => {
  139. userRechargeRef.current?.onOpen &&
  140. userRechargeRef.current?.onOpen(firstPay, index);
  141. }}
  142. />
  143. {item.count_down > 0 ? (
  144. <Timeout
  145. className={
  146. "relative before:left-0 before:top-0 before:content-['']" +
  147. " -m-[0.0417rem] before:h-[100%] before:blur-[0.0486rem]" +
  148. " before:absolute before:-z-10 before:w-[100%] before:bg-[#ed9d00]" +
  149. " text-[0.08rem]" +
  150. " z-1 text-[#fff]"
  151. }
  152. endTime={item.count_down}
  153. onEndHandler={payRun}
  154. />
  155. ) : null}
  156. </div>
  157. );
  158. })}
  159. {/*首充弹窗*/}
  160. <UserRecharge ref={userRechargeRef} />
  161. </>
  162. );
  163. };
  164. /**
  165. * 神秘彩金
  166. */
  167. // const JackpotSection = () => {
  168. // const token = getToken();
  169. // return <div className={clsx("test1232 h-[.4rem] w-[.4rem] bg-[red]")}>2323</div>;
  170. // };
  171. /**
  172. * 红包雨
  173. */
  174. const RedPacketSection = () => {
  175. const token = getToken();
  176. const redPacketModalRef = useRef<RedPacketModalProps>(null);
  177. const getRedPacketInfo = async () => {
  178. try {
  179. let redPacketInfo: any;
  180. let actList: any = [];
  181. if (token) {
  182. redPacketInfo = await lredPacketApi();
  183. actList = redPacketInfo.data?.red_packets || [];
  184. } else {
  185. redPacketInfo = await redPacketApi();
  186. actList = redPacketInfo.data || [];
  187. }
  188. // 已经开始
  189. return actList.filter((aItem: any) => {
  190. return aItem.is_start;
  191. });
  192. } catch (error) {}
  193. };
  194. // 红包雨轮询
  195. const { data: packets, run } = useRequest<any[], any>(getRedPacketInfo, {
  196. pollingInterval: 5000,
  197. pollingErrorRetryCount: 1,
  198. pollingWhenHidden: false,
  199. });
  200. return (
  201. <>
  202. {packets?.map((item, index) => {
  203. const icons = JSON.parse(item.icon);
  204. const icon = icons[icons.length - 1];
  205. return (
  206. <div key={index} className={`mb-[0.2778rem] cursor-pointer`}>
  207. <img
  208. className={"w-[0.54rem] object-fill"}
  209. src={icon}
  210. onClick={() => {
  211. redPacketModalRef.current?.onOpen(packets, index);
  212. }}
  213. />
  214. </div>
  215. );
  216. })}
  217. {/*红包雨弹窗*/}
  218. <RedPacketModal ref={redPacketModalRef} onAfterHandler={run} />
  219. </>
  220. );
  221. };
  222. const MessageSection = () => {
  223. const { unread, userUnred } = useGlobalNoticeStore((state) => ({
  224. unread: state.unread,
  225. userUnred: state.userUnred,
  226. }));
  227. return (
  228. <>
  229. {unread || userUnred ? (
  230. <Link
  231. href={"/notification"}
  232. className={
  233. "mb-[0.2778rem] flex h-[0.54rem] w-[0.54rem] items-center" +
  234. " justify-center rounded-[50%] bg-gradient-to-t from-[#ffa111]" +
  235. " to-[#ffcf35]"
  236. }
  237. >
  238. <Badge content={userUnred + unread} style={{ "--top": "12px" }}>
  239. <i className={"iconfont icon-duanxinguanli text-[0.3rem] text-[#fff]"}></i>
  240. </Badge>
  241. </Link>
  242. ) : null}
  243. </>
  244. );
  245. };
  246. /**
  247. * 客服
  248. */
  249. const CustomerSection: FC<Omit<Props, "socials">> = (props) => {
  250. const { services } = props;
  251. const defaultService = services?.filter((item) => item.is_suspend === 1);
  252. return (
  253. <>
  254. {defaultService?.map((item, index) => (
  255. <Link
  256. key={index}
  257. href={item.url}
  258. className={
  259. "flex h-[0.54rem] w-[0.54rem] items-center justify-center rounded-[50%]" +
  260. " bg-gradient-to-t from-[#ff611b] to-[#ffcf35]"
  261. }
  262. target={"_blank"}
  263. >
  264. <img
  265. className={"h-[0.3889rem] w-[0.3889rem] object-contain"}
  266. src={item.icon_url}
  267. alt={""}
  268. ></img>
  269. </Link>
  270. ))}
  271. </>
  272. );
  273. };
  274. const getMaxSignId = (obj: any) => {
  275. if (!obj) return null;
  276. const signArr: number[] = [];
  277. Object.keys(obj).map((key) => {
  278. if (obj[key] === 9) {
  279. signArr.push(Number(key));
  280. }
  281. });
  282. return signArr.length > 0 ? Math.max(...signArr) : null;
  283. };
  284. /**
  285. * 签到活动
  286. */
  287. const SignInSection: FC = () => {
  288. const SignInRef = useRef<SignInModalProps>(null);
  289. const [activityId, setActivityId] = useState<number | null>(null);
  290. const { getSignData, signData } = useSignStore((state) => {
  291. return {
  292. getSignData: state.getSignData,
  293. signData: state.signData,
  294. };
  295. });
  296. const getUserInfo = async () => {
  297. const res: any = await userInfoApi();
  298. if (res.code === 200 && res.data?.activity) {
  299. const activity_id = getMaxSignId(res.data?.activity);
  300. if (activity_id) {
  301. setActivityId(activity_id);
  302. await getSignData({ activity_id: activity_id });
  303. setTimeout(() => {
  304. signInHandle();
  305. }, 1000);
  306. }
  307. }
  308. };
  309. useEffect(() => {
  310. getUserInfo();
  311. }, []);
  312. const signInHandle = () => {
  313. SignInRef.current?.onOpen();
  314. };
  315. if (!activityId) {
  316. return null;
  317. }
  318. return (
  319. <>
  320. {/* <div
  321. className={
  322. "mt-[0.2778rem] flex h-[0.54rem] w-[0.54rem] items-center justify-center" +
  323. " rounded-[50%]" +
  324. " bg-gradient-to-t from-[#ff611b] to-[#ffcf35]"
  325. }
  326. onClick={signInHandle}
  327. >
  328. Sign
  329. </div> */}
  330. <SignInModal ref={SignInRef}></SignInModal>
  331. </>
  332. );
  333. };
  334. const ServiceWidget: FC<Props> = (props) => {
  335. const { services } = props;
  336. // const [isShowSign, setIsShowSign] = useState(false);
  337. const { eventView } = useEventPoint();
  338. const newServices = services?.filter((item) => item.status === 1) || [];
  339. const getWheel = () => {
  340. if (!getToken()) return Promise.resolve(undefined);
  341. return getWheelApi().then((res) => {
  342. return res.data;
  343. });
  344. };
  345. useEffect(() => {
  346. // 数据存储,侧边栏使用
  347. // setSocials(socials);
  348. // pixel 埋点
  349. // eventView();
  350. }, []);
  351. const t = useTranslations("HomePage");
  352. // const wheelDestory = () => {
  353. // setIsShowSign(true);
  354. // };
  355. return (
  356. <>
  357. <div
  358. className={`absolute bottom-[0.84rem] right-[0.12rem] z-50 flex w-[0.6944rem] flex-col items-center justify-center`}
  359. >
  360. <SlotSection />
  361. {/*轮盘 */}
  362. <WheelSection />
  363. {/*首充*/}
  364. <PaySection />
  365. {/* 红包雨icon */}
  366. <RedPacketSection />
  367. {/*未读消息*/}
  368. <MessageSection />
  369. {/*客服*/}
  370. <CustomerSection services={services} />
  371. {/* 签到 */}
  372. <SignInSection />
  373. </div>
  374. <div
  375. className={`grid`}
  376. style={{
  377. gridTemplateColumns: ` repeat(${newServices && newServices.length >= 5 ? 5 : (newServices?.length ?? 1)},1fr)`,
  378. }}
  379. >
  380. {newServices.map((service, index) => {
  381. return (
  382. <Link
  383. key={index}
  384. href={service.url}
  385. target={"_blank"}
  386. className="bg-white m-[0.05rem] h-[0.3889rem] w-[0.3889rem] rounded"
  387. >
  388. <img
  389. className={"h-[0.3889rem] w-[0.3889rem]"}
  390. src={service.icon_url}
  391. ></img>
  392. </Link>
  393. );
  394. })}
  395. </div>
  396. <div className={"text-[#ced1ff]"}>{t("Service")}</div>
  397. {/*share*/}
  398. <div className={"my-[0.2rem] text-[0.12rem] text-[#ced1ff]"}>{t("Share")}</div>
  399. <Image
  400. src={"/logo2.png"}
  401. alt={"BCWIN777"}
  402. width={120}
  403. height={180}
  404. className={"mb-[0.2rem]"}
  405. />
  406. </>
  407. );
  408. };
  409. export default ServiceWidget;